﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Core.Interfaces;

namespace Core.DatabaseHelpers
{
    public static class ColumnHelper
    {

        

        public static string GetListOfColumns<T>(bool isLazy)
        {
            var p = typeof(T).GetProperties().Where(x => x.GetCustomAttributes(typeof(ColumnAttribute),false).Length > 0);
            var result = new List<string>();
            if (!isLazy)
            {
                 result = (from propertyInfo in p
                              select (ColumnAttribute)propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false).First()
                                  into attr
                                  where attr.IsField
                                  select attr.Name).ToList();
            }
            else
            {
                result = (from propertyInfo in p
                              select (ColumnAttribute)propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false).First()
                                  into attr
                                  select attr.Name).ToList();
            }
            
            var columns = result.Aggregate("", (current, s) => current + (s + ','));
            return columns.Substring(0, columns.Length - 1);
        }


        public static Dictionary<string ,string > GetKeyValuePairFromRow<T>(object[] row)
        {
            var p = typeof(T).GetProperties();
            var result = (from propertyInfo in p
                          select (ColumnAttribute)propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false).First()
                              into attr
                              where attr.IsField
                              select attr.Name).ToList();
            return result.ToDictionary(s => s, s => row.ToString());
        }

        public static Dictionary<string ,string> GetColumValue<T>(object domainObject)
        {
            var p = typeof(T).GetProperties();
            var result = new Dictionary<string, string>();
            foreach (PropertyInfo propertyInfo in p)
            {
                var list_of_attr = propertyInfo.GetCustomAttributes(typeof (ColumnAttribute), false);
                ColumnAttribute attr = null;
                if (list_of_attr.Any())
                {
                     attr =(ColumnAttribute)list_of_attr.First();
                     if (attr.IsField && attr.IsFillIn)
                     {
                         var v = propertyInfo.GetValue(domainObject, null);
                         var s = "";
                         if (v is DateTime)
                         {
                             var date = (DateTime)v;
                             s = "'" + date.Year.ToString() + '/' + date.Month.ToString() + '/' + date.Day.ToString() + "'";
                         }
                         else
                         {
                             if (v.GetType().Name == "String")
                             {
                                 s = "'" + v.ToString() + "'";
                             }
                             else
                             {
                                 s = v.ToString();
                             }

                         }
                         result.Add(attr.Name, s);
                     }
                     else
                     {
                         if (attr.IsChild)
                         {
                             object v = propertyInfo.GetValue(domainObject, null);
                             var c = v.GetType().GetInterfaces().First(x => x.GetCustomAttributes(typeof(TableAttribute), false).Any());
                             var pp = c.GetProperties().First(
                                 x => ((ColumnAttribute)x.GetCustomAttributes(typeof(ColumnAttribute), false).First()).IsPK
                                 && ((ColumnAttribute)x.GetCustomAttributes(typeof(ColumnAttribute), false).First()).Name == attr.Name);
                             var s = "";
                             var uxu = pp.GetValue(v, null);
                             if (uxu.GetType().Name == "String")
                             {
                                 s = "'" + uxu.ToString() + "'";
                             }
                             else
                             {
                                 s = uxu.ToString();
                             }
                             result.Add(attr.Name,s );
                         }
                     }
                }
               
                
                   
            }
            return result;
        }



        public static int ColumnCounter<T>(bool isLazy)
        {
            if (!isLazy)
            {
                return typeof(T).GetProperties().Where(x => x.GetCustomAttributes(typeof(ColumnAttribute), false).Length > 0).Select(property => (ColumnAttribute)property.GetCustomAttributes(typeof(ColumnAttribute), false).Last()).Count(attr => attr.IsField);
            }
            else
            {
                return typeof(T).GetProperties().Where(x => x.GetCustomAttributes(typeof(ColumnAttribute), false).Length > 0).Select(property => (ColumnAttribute)property.GetCustomAttributes(typeof(ColumnAttribute), false).Last()).Count();
                
            }
        }

        public static  KeyValuePair<string,string> GetPkNameAndValue(object o)
        {
            var c = o.GetType().GetInterfaces().First(x => x.GetCustomAttributes(typeof(TableAttribute), false).Any());
            var pp = c.GetProperties().First(
                           x => ((ColumnAttribute)x.GetCustomAttributes(typeof(ColumnAttribute), false).First()).IsPK);
            var s = "";
            if (!(pp.GetValue(o,null).GetType().Name == "Building"))
            {
                s= pp.GetValue(o, null).ToString();    
            }
            else
            {
                s = ((IBuilding)pp.GetValue(o, null)).RegisterID;
                s = "'" + s + "'";
            }
            

            if (pp.GetValue(o,null).GetType().Name == "String")
            {
                s = "'" + s + "'";
            }
            var result = new KeyValuePair<string, string>(((ColumnAttribute)pp.GetCustomAttributes(typeof(ColumnAttribute),false).First()).Name,s);
            return result;
        }

        public static T To<T>(this string stringValue)
        {
           return (T)Convert.ChangeType(stringValue, typeof(T));
        }


        public static string WherePKIs<T>(object o)
        {
            var p = typeof(T).GetProperties();
            var key_name = (from propertyInfo in p
                            select
                                (ColumnAttribute)
                                propertyInfo.GetCustomAttributes(typeof (ColumnAttribute), false).First()
                            into attr
                            where attr.IsPK
                            select attr.Name);
            return key_name.First();
        }

        public static void ConstructDomainObject<T>(Dictionary<string ,string > dictionary,object domain)
        {
            var p = typeof(T).GetProperties();
            foreach (PropertyInfo propertyInfo in p)
            {
              
                var ca = (ColumnAttribute) propertyInfo.GetCustomAttributes(typeof (ColumnAttribute), false).First();
                
                propertyInfo.SetValue(domain,To<DateTime>(dictionary[ca.Name]),null);
                
            }
        }

        public static List<KeyValuePair<string,string>> GetPrimaryKeys<T>(object domain)
        {
            var p = typeof(T).GetProperties();
            var result = new List<KeyValuePair<string, string>>();
            foreach (var propertyInfo in p)
            {
                var ca = propertyInfo.GetCustomAttributes(typeof (ColumnAttribute), false);
                if (ca.Any())
                {
                    var attr = (ColumnAttribute)ca.First();
                    if (attr.IsPK)
                    {
                        var v = propertyInfo.GetValue(domain, null);
                        var s = v.ToString();
                        if (v.GetType().Name == "String")
                        {
                            s = "'" + s + "'";
                        }
                        result.Add(new KeyValuePair<string, string>(attr.Name,s ));
                    }
                }
            }
            return result;
        } 

        public static bool HasManyToMany<T>()
        {
            var p = typeof(T).GetProperties();
            return (from propertyInfo in p select propertyInfo.GetCustomAttributes(typeof (ColumnAttribute), false) into ca where ca.Any() select (ColumnAttribute) ca.First()).Any(attr => attr.IsManyToMany);
        }


        public static PropertyInfo GetHasManyField<T>()
        {
            var p =typeof(T).GetProperties();
            return p.First(x => ((ColumnAttribute) x.GetCustomAttributes(typeof (ColumnAttribute), false).First()).IsManyToMany);
        }
    }
}
